/*********************************************
 Filename: Linkedl2a.c 
 Purpose:  Based on the quene code, PCB was added as the 
 element of the listNode struct. 
 Date: October 4, 2008 
 Modifications: 
 1. char *data changed to PCB *data
 2. since 5 states have been predefined,it should be a int type 
    quene_id. The name of the PCB and the state of PCB are used 
    as the identifier in all functions. 

**********************************************/ 

#include <stdio.h>
#include <stdlib.h>
#include "PCB.c" 
#include "mpx_supt.c" 

#define SIZE 20

struct listNode
{
	PCB *data;
	struct listNode *nextPtr;
};

typedef struct listNode ListNode;
typedef ListNode *ListNodePtr;

struct list{
	ListNodePtr head;
      
};

typedef struct list List;
typedef List *ListPtr;
/*
typedef struct list Ready;
typedef Ready *ReadyPtr;
typedef struct list Wait;
typedef Wait *WaitPtr;
typedef struct list Block;
typedef Block *BlockPtr;
typedef struct SusReady;
typedef SusReady *SusReadyPtr;
typedef struct list SusBlock;
typedef SusBlock *SusBlockPtr;
*/

ListPtr ReadyQueue;
ListPtr RunningQueue;
ListPtr BlockQueue;
ListPtr SusReadyQueue;
ListPtr SusBlockQueue;

void queue_init(void);
PCB* find_pcb(char *value);
void show(int quene_id);
void insertpcb(char *data_name, int quene_id);
void removepcb(char *data_name, int quene_id);
void insert(ListPtr sPtr, char *data_name);
char delete(ListPtr sPtr, char *data_name);
int isEmpty(ListPtr sPtr);
void printList(ListPtr currPtr);
void instructions(void);

void queue_init(void){
ReadyQueue = sys_alloc_mem(sizeof(List));
ReadyQueue->head=NULL;
RunningQueue = sys_alloc_mem(sizeof(List));
WaitQueue->head=NULL;
BlockQueue = sys_alloc_mem(sizeof(List));
BlockQueue->head=NULL;
SusReadyQueue = sys_alloc_mem(sizeof(List));
SusReadyQueue->head=NULL;
SusBlockQueue = sys_alloc_mem(sizeof(List));
SusBlockQueue->head=NULL;
}

/***************************************************** 
Purpose: Find pcb with the name as value from a certain quene 
Precondition:  quene_init() has been convoked. 
*****************************************************/ 
PCB* find_pcb(ListPtr sPtr, char *value){
  
  ListNodePtr currPtr;
  if (!isEmpty(ListPtr sPtr)) 
 {
  currPtr = sPtr->head->nexPtr; 
    while (currPtr!=NULL)
     {
    if (!strcmp(currPtr->data->pcb_name, value))
     return currPtr; 
    else
     currPtr=currPtr->nexPtr; 
    }
  
  }
  else 
  return  NULL; 
}

/* Find the pcb in al 5 quenes */ 
PCB* findall_pcb(char *value) {
  PCB* tPCB = allo_pcb();
  
 if ((tPCB = find_pcb(RunningQuene, value))!=NULL)
 return tPCB;
  elseif ((tPCB = find_pcb(ReadyQuene, value))!=NULL)
  return tPCB; 
    elseif ((tPCB = find_pcb(BlockQuene, value))!=NULL)
    return tPCB; 
      elseif ((tPCB = find_pcb(SusReadyQuene, value))!=NULL)
      return tPCB; 
        else
          return (tPCB = find_pcb(SusBlockQuene, value));
  
}

void set_priority(char *value, int pri){
// make sure PCB with the name of value exists
 PCB*  sPCB;
 if (findall_pcb(value)!=NULL)
 {
  sPCB = findall_pcb(value);
  strcpy(sPCB->pcb_priority,pri); 

 }
 else
 {
  printf( " This PCB does not exist."); 
 }


}

void insertpcb(PCB* data, int quene_id){

	if(quene_id=1000){
	   insert(ReadyQueue, data);
	}
	else if(quene_id=2000){
	   insert(WaitQueue, data);
	}
	else if(quene_id=3000){
	   insert(BlockQueue, data);
	}
	else if(quene_id=4000){
	   insert(SusReadyQueue, data);
	}
	else if(quene_id=5000){
	   insert(SusBlockQueue, data);
	}
	else{
	   printf("Invalid process state!\n");
	   return;
	}
}
void removepcb(char *data_name, char *queue){
	if(!strcmp(queue,"ready")){
	   if(!isEmpty(ReadyQueue)){
	      if(delete(ReadyQueue, data)){
		 printf("%s deleted.\n", data);
		 }
	      else
		 printf("%s not found.\n", data);
	      }
	      else if(isEmpty(ReadyQueue)){
		 printf("List is empty.\n");
		 return;
	      }
	}
	else if(!strcmp(queue, "waiting")){
	   if(!isEmpty(WaitQueue)){
	      if(delete(WaitQueue, data)){
		 printf("%s deleted.\n", data);
		 }
	      else
		 printf("%s not found.\n", data);
	      }
	      else if(isEmpty(WaitQueue)){
		 printf("List is empty.\n");
		 return;
	      }
	}
	else if(!strcmp(queue, "blocked")){
	   if(!isEmpty(BlockQueue)){
	      if(delete(BlockQueue, data)){
		 printf("%s deleted.\n", data);
		 }
	      else
		 printf("%s not found.\n", data);
	      }
	      else if(isEmpty(BlockQueue)){
		 printf("List is empty.\n");
		 return;
	      }
	}
	else if(!strcmp(queue, "suspended-ready")){
	   if(!isEmpty(SusReadyQueue)){
	      if(delete(SusReadyQueue, data)){
		 printf("%s deleted.\n", data);
		 }
	      else
		 printf("%s not found.\n", data);
	      }
	      else if(isEmpty(SusReadyQueue)){
		 printf("List is empty.\n");
		 return;
	      }
	}
	else if(!strcmp(queue, "suspended-blocked")){
	   if(!isEmpty(SusBlockQueue)){
	      if(delete(SusBlockQueue, data)){
		 printf("%s deleted.\n", data);
		 }
	      else
		 printf("%s not found.\n", data);
	      }
	      else if(isEmpty(SusBlockQueue)){
		 printf("List is empty.\n");
		 return;
	      }
	}
	else{
	   printf("Invalid process state!\n");
	   return;
	}
}
void show (char *queue){
	if(!strcmp(queue,"ready")){
	   printf ("Printing Ready Queue:\n");
	   printList(ReadyQueue);
	}
	else if(!strcmp(queue, "waiting")){
	   printList(WaitQueue);
	}
	else if(!strcmp(queue, "blocked")){
	   printList(BlockQueue);
	}
	else if(!strcmp(queue, "suspended-ready")){
	   printList(SusReadyQueue);
	}
	else if(!strcmp(queue, "suspended-blocked")){
	   printList(SusBlockQueue);
	}
	else{
	   printf("Invalid process state!\n");
	   return;
	}
}


void insert(ListPtr sPtr, PCB *value)
{
	ListNodePtr newPtr;
	ListNodePtr prevPtr;
	ListNodePtr currPtr;

	newPtr = malloc(sizeof(ListNode));
	newPtr->nextPtr=NULL;
	newPtr->data = malloc(strlen(value)+1 * sizeof(PCB));

	strcpy(newPtr->data, value);


	if(newPtr !=NULL){

		prevPtr = NULL;
		currPtr = sPtr->head;

		if (currPtr == NULL) {
			sPtr->head = newPtr;
			return;
		}
		while(currPtr != NULL && strcmp(value, currPtr -> data) > 0 )
		{
			prevPtr = currPtr;
			currPtr = currPtr ->nextPtr;
		}

		if(prevPtr == NULL)
		{
			newPtr -> nextPtr = sPtr->head;
			sPtr->head = newPtr;
		}
		else if( prevPtr != NULL && currPtr != NULL)
		{
			prevPtr -> nextPtr = newPtr;
			newPtr -> nextPtr = currPtr;
		}
		else if(prevPtr != NULL && currPtr == NULL)
		{
		   prevPtr->nextPtr = newPtr;
		}
	}
	else
	{
		printf("Not inserted. No memory avaliable.\n");
	}
}

char delete(ListPtr sPtr, PCB *value)
{
	ListNodePtr tempPtr=NULL;
	ListNodePtr prevPtr=NULL;
	ListNodePtr currPtr;

	if(strcmp(value, sPtr -> head ->data) == 0)
	{

		tempPtr =sPtr->head;
		sPtr->head = sPtr->head->nextPtr;
		free(tempPtr->data);
		free(tempPtr);
		return 1;
	}
	else
	{
		prevPtr = sPtr->head;
		currPtr = prevPtr->nextPtr;

		while(currPtr != NULL && strcmp(currPtr -> data, value) !=0)
		{
			prevPtr = currPtr;
			currPtr = currPtr ->nextPtr;
		}

		if(currPtr != NULL)
		{
			tempPtr = currPtr;
			prevPtr -> nextPtr = currPtr -> nextPtr;
			free(tempPtr->data);
			free(tempPtr);
			return 1;
		}
	}
	return 0;
}

int isEmpty(ListPtr sPtr)
{
	return (sPtr->head == NULL);
}


void printList(ListPtr currPtr)
{
	ListNodePtr next;

	if(currPtr->head == NULL)
	{
		printf("List is empty.\n");
	}
	else
	{
		printf("The list is: \n");
		next = currPtr->head;

		while(next != NULL)
		{
			printf("%12s  ", next -> data->pcb_name);
                  printf("%4d  ", next -> data->pcb_class);
                  printf("%6d  ", next -> data->pcb_state);
                  printf("%4d  ", next -> data->pcb_priority);

			next = next->nextPtr;
		}
		printf("NULL\n");
	}
}





//ADDED BY JIHAD - 9:30PM  10/06/08
//Finds a PCB in ANY que and removes it from that que
PCB* removeall_pcb(char *p)
{
	PCB* tPCB=allo_pcb();

	//Search Queues for *p pcb, return to procob
	//and remove pcb for queue
 	if ((tPCB = find_pcb(RunningQueue, p))!=NULL)
 	{remove(p,RunningQueue);return tPCB;}
  	elseif ((tPCB = find_pcb(ReadyQueue, p))!=NULL)
 	{remove(p,ReadyQueue);return tPCB;}
    	elseif ((tPCB = find_pcb(BlockQueue, p))!=NULL)
 	{remove(p,BlockQueue);return tPCB;}
      	elseif ((tPCB = find_pcb(SusReadyQueue, p))!=NULL)
 	{remove(p,SusReadyQueue);return tPCB;}
        elseif ((tPCB = find_pcb(SusBlockQueue, p))!=NULL)
	{remove(p,SusReadyQueue);return tPCB;}
	else
		errorHPCB(000);
}

void errorHPCB(int err)
{
	switch(err)
	{
		case 000:         //PCB NOT FOUND
		printf("\n\nERROR: PCB does not exist or error in PCB search");
		break;
		case 001:
		printf("\n\nERROR: State no recognized");
		break;
		default:
		printf("\n\nERROR: Unkown Error");
		//add new error cases here
	}
}